package mylittleinvestigations.Collisions;

import java.io.IOException;
import java.util.ArrayList;
import mylittleinvestigations.CaseInformation.CaseXmlReader;
import mylittleinvestigations.CaseInformation.CaseXmlWriter;
import mylittleinvestigations.Vector2;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;

public class HitBox
{
    private ArrayList<CollidableObject> collidableObjectList;
    private Rectangle areaBoundsRectangle;

    public HitBox()
    {
        this.collidableObjectList = new ArrayList<CollidableObject>();
    }

    public void AddCollidableObject(CollidableObject collidableObject)
    {
        this.collidableObjectList.add(collidableObject);
    }
    
    public void AddAreaBounds(Rectangle areaBoundsRectangle)
    {
        this.areaBoundsRectangle = areaBoundsRectangle;
    }

    public boolean IsCollision(Vector2 offset, HitBox hitBox, Vector2 hitBoxOffset, CollisionParameter param)
    {
        boolean isCollision = false;
        Vector2 overlapCompensation = new Vector2(0, 0);

        for (int i = 0; i < this.collidableObjectList.size(); i++)
        {
            CollidableObject collidableObject1 = this.collidableObjectList.get(i);
            
            for (int j = 0; j < hitBox.collidableObjectList.size(); j++)
            {
                CollidableObject collidableObject2 = hitBox.collidableObjectList.get(j);
                CollisionParameter tempParam = new CollisionParameter();

                if (Collision.IsCollision(collidableObject1, offset.add(overlapCompensation), collidableObject2, hitBoxOffset, tempParam)
                    && Math.abs(tempParam.OverlapDistance) > 0.0001f)
                {
                    param.OverlapEntryList.addAll(tempParam.OverlapEntryList);
                    
                    overlapCompensation = overlapCompensation.add(tempParam.OverlapAxis.scalarMultiply(tempParam.OverlapDistance));
                    isCollision = true;
                }
            }
        }

        param.OverlapDistance = (float)overlapCompensation.length();
        param.OverlapAxis = overlapCompensation.normalize();
        return isCollision;
    }
    
    public Rectangle GetBoundingBox()
    {
        double left = Double.POSITIVE_INFINITY;
        double top = Double.POSITIVE_INFINITY;
        double right = Double.NEGATIVE_INFINITY;
        double bottom = Double.NEGATIVE_INFINITY;
        
        for (int i = 0; i < this.collidableObjectList.size(); i++)
        {
            ArrayList<Vector2> vertices = this.collidableObjectList.get(i).getVertices();
            
            for (int j = 0; j < vertices.size(); j++)
            {
                Vector2 vertex = vertices.get(j);
                
                if (vertex.getX() < left)
                {
                    left = vertex.getX();
                }
                
                if (vertex.getX() > right)
                {
                    right = vertex.getX();
                }
                
                if (vertex.getY() < top)
                {
                    top = vertex.getY();
                }
                
                if (vertex.getY() > bottom)
                {
                    bottom = vertex.getY();
                }
            }
        }
        
        return new Rectangle((float)left, (float)top, (float)(right - left), (float)(bottom - top));
    }
    
    public void Draw(Vector2 topLeftCornerPosition, GameContainer gc, Graphics g)
    {
        for (int i = 0; i < this.collidableObjectList.size(); i++)
        {
            this.collidableObjectList.get(i).Draw(topLeftCornerPosition, gc, g);
        }
    }

    public void SaveToXml(CaseXmlWriter writer) throws IOException
    {
        writer.StartElement("HitBox");
        writer.StartElement("CollidableObjectList");
        
        for (int i = 0; i < this.collidableObjectList.size(); i++)
        {
            writer.StartElement("Entry");
            this.collidableObjectList.get(i).SaveToXml(writer);
            writer.EndElement();
        }
        
        writer.EndElement();
        
        if (this.areaBoundsRectangle != null)
        {
            writer.StartElement("AreaBoundsRectangle");
            writer.WriteRectangleElement(this.areaBoundsRectangle);
            writer.EndElement();
        }
        
        writer.EndElement();
    }

    public HitBox(CaseXmlReader reader)
    {
        this.collidableObjectList = new ArrayList<CollidableObject>();
        
        reader.StartElement("HitBox");
        reader.StartElement("CollidableObjectList");
        
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            CollidableObject collidableObject = new CollidableObject(reader);
            this.collidableObjectList.add(collidableObject);
        }
        
        reader.EndElement();
        
        if (reader.ElementExists("AreaBoundsRectangle"))
        {
            reader.StartElement("AreaBoundsRectangle");
            this.areaBoundsRectangle = reader.ReadRectangleElement();
            reader.EndElement();
        }
        
        reader.EndElement();
    }
}